//
// Created by ftd on 2021/8/18.
//

#include "demo.h"
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include "config/system_config.h"
#include "net_msg/net_msg_manager.h"
#include "handle/net_msg_event_handle.h"

namespace {
// 程序退出
void Stop(int sig) {
    Demo::Instance().Exit();
}
}

Demo& Demo::Instance() {
    static Demo instance;
    return instance;
}

Demo::Demo()
        : is_exit_(false)
        , is_stress_test_(false) {
}

Demo::~Demo() {
    for (auto& th : handle_threads_) {
        if (th.joinable())
            th.join();
    }
}

void Demo::Exit() {
    is_exit_ = true;
    cond_.notify_all();
    fprintf(stdout, "process exit\n");
    //do something ...
}

bool Demo::StartUp(int argc, char **argv) {
    int code = 0;
    if (argc > 1) {
        if (0 == strcmp("-daemon", *(argv + 1))) {
            code = daemon(1, 0);
        }
        else if (0 == strcmp("-stress", *(argv + 1))) {
            is_stress_test_ = true;
        }
    }
    if (0 == code) {
        signal(SIGTERM, Stop);
        if (!SystemConfig::Instance().LoadConig()) {
            return false;
        }
        NetMsgEventHandle::Instance().RegisterEventHandle();
    } else {
        fprintf(stderr,"fork child process failed!");
        return false;
    }
    return true;
}

void Demo::Run() {
    NetMsgManager::Instance().Run();
    StartHandleThread();

    // 1秒帧数
    int8_t fps = 10;
    // 每帧间隔时间（毫秒）
    auto frameTime = 1000 / fps;
    auto start_tick_count = std::chrono::steady_clock::now();
    double loss_tick_count = 0.f;
    time_t last_loss_tick_count = 0;
    auto& net_msg_event_handle = NetMsgEventHandle::Instance();
    for (; !is_exit_;) {
        loss_tick_count = std::chrono::duration<double, std::milli>(
                std::chrono::steady_clock::now() - start_tick_count).count();
        if (loss_tick_count >= last_loss_tick_count + frameTime) {
            last_loss_tick_count += frameTime;
            //do something ...
            if (is_stress_test_) {
                if (last_loss_tick_count % 1000 == 0) {
                    net_msg_event_handle.Update();
                }
            }
        } else {
            std::this_thread::sleep_for(
                    std::chrono::milliseconds(frameTime - (int) (loss_tick_count - last_loss_tick_count)));
        }
    }
    return;
}

void Demo::PutMsg(uint8_t *msg_buffer, int msg_size) {
    std::unique_lock<std::mutex> lock(mutex_);
    ring_buffer_.PutData(msg_buffer, msg_size);
    cond_.notify_all();
}

bool Demo::StartHandleThread() {
    auto thread_cnt = std::thread::hardware_concurrency() / 2;
    if (0 == thread_cnt)
        thread_cnt = 1;
    handle_threads_.resize(thread_cnt);
    for (unsigned int i = 0; i < thread_cnt; ++i) {
        handle_threads_[i] = std::thread(&Demo::HandleEvent, this);
    }
    return false;
}

void Demo::HandleEvent() {
    uint8_t msg_buffer[200] = {0};
    auto msg_head = (MsgHead*)msg_buffer;
    int msg_head_size = sizeof(MsgHead);
    auto& net_msg_event_handle = NetMsgEventHandle::Instance();
    for (;!is_exit_;) {
        {
            std::unique_lock<std::mutex> lock(mutex_);
            if (ring_buffer_.GetData(msg_head, msg_head_size)) {
                if (ring_buffer_.GetData(msg_head + 1, msg_head->msg_size)) {
                    net_msg_event_handle.EventHandle(msg_head->msg_id, msg_head+1, msg_head->msg_size);
                } else {
                    assert(false);
                }
            } else {
                cond_.wait(lock);
            }
        }
    }
}
